﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using haptic.src.engine.render;

namespace haptic.src.engine.animation
{
    public class SpriteInstance
    {
        public enum State
        {
            E_STOPPED = 0,
            E_PLAYING,
            E_PAUSED
        }
        public enum Mode
        {
            E_LOOP = 0,
            E_PLAY_ONCE,
            E_STAY_ON_LAST_FRAME
        }
        #region Constructors
        public SpriteInstance(){}
        public SpriteInstance(Sprite oSprite)
        {
            m_oSprite = oSprite;
            m_oRect = new Rectangle(0, 0, (int)m_oSprite.m_uiFrameWidth, (int)m_oSprite.m_uiFrameHeight);
        }
        #endregion

        #region Control
        public void Play()
        {
            if (m_eState == State.E_STOPPED)
            {
                m_fElapsedTime = 0.0f;
            }
            m_eState = State.E_PLAYING;
        }
        public void Stop()
        {
            m_eState = State.E_STOPPED;
        }
        public void Pause()
        {
            m_eState = State.E_PAUSED;
        }
        #endregion

        #region Update
        private void UpdateLoop(GameTime oTime)
        {
            float fTimeRatio = m_fElapsedTime / m_oSprite.fTotalDuration;
            fTimeRatio -= (float)(uint)(fTimeRatio);
            m_uiFrameIndex = (uint)(fTimeRatio * (float)m_oSprite.m_uiFrameCount);
            
        }
        private void UpdatePlayOnce(GameTime oTime)
        {
            if (m_fElapsedTime >= m_oSprite.fTotalDuration)
            {
                m_uiFrameIndex = 0;
                m_eState = State.E_STOPPED;
            }
            else
            {
                float fTimeRatio = m_fElapsedTime / m_oSprite.fTotalDuration;
                m_uiFrameIndex = (uint)(fTimeRatio * (float)m_oSprite.m_uiFrameCount);
            }
        }
        private void UpdateStayOnLastFrame(GameTime oTime)
        {
            if (m_fElapsedTime >= m_oSprite.fTotalDuration)
            {
                m_uiFrameIndex = m_oSprite.m_uiFrameCount-1;
            }
            else
            {
                float fTimeRatio = m_fElapsedTime / m_oSprite.fTotalDuration;
                m_uiFrameIndex = (uint)(fTimeRatio * (float)m_oSprite.m_uiFrameCount);
            }
        }
        public void Update(GameTime oTime)
        {
            if (m_eState == State.E_PLAYING)
            {
                m_fElapsedTime += (float)oTime.ElapsedGameTime.TotalSeconds;
                switch (m_eMode)
                {
                case Mode.E_PLAY_ONCE:
                        UpdatePlayOnce(oTime);
                	break;
                case Mode.E_LOOP:
                        UpdateLoop(oTime);
                    break;
                case Mode.E_STAY_ON_LAST_FRAME:
                        UpdateStayOnLastFrame(oTime);
                    break;
                }
                m_oRect.X = (int)(m_uiFrameIndex * m_oSprite.m_uiFrameWidth);
            }
        }
        #endregion
        #region Draw
        public void Draw(Renderer oRenderer, Vector2 vPos)
        {
            oRenderer.DrawSprite(m_oSprite, vPos, m_oRect);
        }
        #endregion
        #region Attributes
        private Sprite m_oSprite;
        public Sprite oSprite { get { return m_oSprite; } }
        private uint m_uiFrameIndex = 0;
        public uint uiFrameIndex { get { return m_uiFrameIndex; } }
        private Rectangle m_oRect;
        private float m_fElapsedTime = 0.0f;
        private State m_eState = State.E_STOPPED;
        public Mode m_eMode = Mode.E_LOOP;

        #endregion
    }
}
